Operazioni preliminari che ci hanno permesso di lavorare con il dataset sono state:
# Import delle librerie
#import for Numpy
import numpy as np
#import for Plotly
import plotly.express as px
import plotly.graph_objects as go
#import for Pandas
import pandas as pd
from datetime import datetime
df_earthQuake = pd.read_csv("data/EarthQuake/Earthquakes historical data from 1800 to 2021.csv")
df_toMerge1 = pd.read_csv("data/EarthQuake/earthquakes_secondCSV.csv")
df_toMerge2 = pd.read_csv("data/EarthQuake/Worldwide-Earthquake-database.csv")
La funzione add_date_col accetta un DataFrame contenente colonne separate per anno, mese, giorno e tempo. Crea una nuova colonna 'Date' combinando queste informazioni, gestisce le conversioni di tipo e aggiunge eventuali offset di tempo definiti nelle colonne di ora, minuto e secondo. Infine, elimina le righe con date mancanti e colonne non necessarie, restituendo il DataFrame modificato.
def add_date_col(df_passed):
main_cols = ['Year', 'Mo', 'Dy']
add_cols = ['Hr', 'Mn', 'Sec']
df = df_passed.dropna(subset=main_cols).copy()
for col in main_cols:
df[col] = df[col].astype(int).astype(str)
df[main_cols[-2:]] = df[main_cols[-2:]].apply(lambda col: col.apply(lambda x: str(x).zfill(2)))
df['Date'] = df[main_cols].agg('-'.join, axis=1)
df['Date'] = pd.to_datetime(df['Date'], format='%Y-%m-%d', errors='coerce')
df = df[['Date'] + [col for col in df.columns if col != 'Date']]
valid_time = df[add_cols].notna().any(axis=1)
for col in add_cols:
df[col] = df[col].apply(lambda x: str(int(round(x))) if pd.notna(x) else '00').str.zfill(2)
time_delta_str = df.loc[valid_time, add_cols].agg(':'.join, axis=1)
time_delta = pd.to_timedelta(time_delta_str, errors='coerce')
df.loc[valid_time, 'Date'] += time_delta
df.dropna(subset=['Date'], inplace=True)
df.drop(main_cols+add_cols, axis=1, inplace=True)
return df
La funzione clean_dataset effettua una serie di operazioni di pulizia su un DataFrame. Rimuove una colonna specifica, normalizza i nomi delle colonne, rinomina alcune colonne per chiarezza, e converte alcune colonne in formato numerico. In particolare, gestisce la colonna 'Tsu' trasformando i valori 'Yes' in 1 e 'No' in 0, e converte le colonne 'Sec', 'Longitude' e 'Latitude' in numeri, trattando eventuali errori di conversione. Il DataFrame risultante è più pulito e pronto per il merging e per ulteriori analisi.
def clean_dataset(df):
df.drop('I_D', axis=1, inplace=True)
df.columns = [col.replace('_', ' ').title() for col in df.columns]
df.columns = [col.title() for col in df.columns]
df.rename(columns={
'Month':'Mo', 'Day':'Dy', 'Hour':'Hr', 'Minute':'Mn', 'Second':'Sec', 'Focal Depth':'Focal Depth (km)',
'Total Deaths Description':'Total Death Description', 'Deaths Description':'Death Description',
'Total Damage Millions Dollars':'Total Damage ($Mil)', 'Damage Millions Dollars':'Damage ($Mil)',
'Flag Tsunami':'Tsu', 'Eq Primary':'Mag', 'Intensity':'MMI Int'
}, inplace=True)
col_to_convert = ['Sec','Longitude', 'Latitude']
df[col_to_convert] = df[col_to_convert].apply(pd.to_numeric, errors='coerce')
df['Tsu'] = df['Tsu'].replace({'Yes':1, 'No':0}).astype(float)
return df
df_toMerge2 = clean_dataset(df_toMerge2)
df_cleaned1 = add_date_col(df_earthQuake)
df_cleaned2 = add_date_col(df_toMerge1)
df_cleaned3 = add_date_col(df_toMerge2)
Procediamo con l'unione dei tre DataFrames (df_cleaned1, df_cleaned2, e df_cleaned3) al fine di costituire un nuovo DataFrame denominato "dataset_combinato". Questo insieme di dati aggregato è caratterizzato dall'assenza di duplicati riscontrati nelle colonne 'Date', 'Longitude' e 'Latitude'.
Successivamente, generiamo un DataFrame denominato "df_merged" attraverso l'operazione di fusione tra "dataset_combinato" e una selezione specifica di colonne provenienti da "df_cleaned3". Tale operazione di fusione si basa sulle colonne 'Date', 'Longitude', e 'Latitude', e si concretizza mantenendo integralmente tutte le righe provenienti da "dataset_combinato".
Successivamente, procediamo all'eliminazione dei duplicati basati sulle colonne 'Date', 'Longitude', e 'Latitude'. Il DataFrame risultante, df_merged, viene ordinato in base alla colonna 'Date'. Infine, le righe contenenti valori mancanti nella colonna 'Mag' vengono diligentemente rimosse dal dataset risultante.
dataset_combinato = pd.concat([df_cleaned1, df_cleaned2], ignore_index=True).drop_duplicates(subset=['Date','Longitude','Latitude'])
df3_columns = ['Date', 'Longitude', 'Latitude', 'Eq Mag Ms', 'Eq Mag Unk', 'Eq Mag Mw', 'Eq Mag Mb', 'Country', 'Eq Mag Mfa', 'Region Code', 'State']
df_merged = pd.merge(dataset_combinato,
df_cleaned3[df3_columns],
left_on=['Date', 'Longitude', 'Latitude'],
right_on=['Date', 'Longitude', 'Latitude'],
how='left')
df_merged = pd.concat([df_merged, df_cleaned3], ignore_index=True).drop_duplicates(subset=['Date','Longitude','Latitude'])
df_merged = df_merged.sort_values(by='Date')
df_merged = df_merged.reset_index(drop=True)
df_merged = df_merged.dropna(subset=['Mag'])
Qui di seguito é possibile visionare tutte le colonne presenti nel dataset e i loro tipi
df_merged.dtypes
Date datetime64[ns] Tsu float64 Vol float64 Location Name object Latitude float64 Longitude float64 Focal Depth (km) float64 Mag float64 MMI Int float64 Deaths float64 Death Description float64 Missing float64 Missing Description float64 Injuries float64 Injuries Description float64 Damage ($Mil) float64 Damage Description float64 Houses Destroyed float64 Houses Destroyed Description float64 Houses Damaged float64 Houses Damaged Description float64 Total Deaths float64 Total Death Description float64 Total Missing float64 Total Missing Description float64 Total Injuries float64 Total Injuries Description float64 Total Damage ($Mil) float64 Total Damage Description float64 Total Houses Destroyed float64 Total Houses Destroyed Description float64 Total Houses Damaged float64 Total Houses Damaged Description float64 Eq Mag Ms float64 Eq Mag Unk float64 Eq Mag Mw float64 Eq Mag Mb float64 Country object Eq Mag Mfa float64 Region Code float64 State object Eq Mag Ml float64 dtype: object
Il dataset parsato e pulito alla fine risulta come segue:
df_merged
| Date | Tsu | Vol | Location Name | Latitude | Longitude | Focal Depth (km) | Mag | MMI Int | Deaths | ... | Total Houses Damaged Description | Eq Mag Ms | Eq Mag Unk | Eq Mag Mw | Eq Mag Mb | Country | Eq Mag Mfa | Region Code | State | Eq Mag Ml | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1677-11-04 00:00:00 | 322.0 | NaN | JAPAN: OFF SE. BOSO PENINSULA | 35.000 | 141.500 | NaN | 7.4 | NaN | NaN | ... | NaN | 7.4 | NaN | NaN | NaN | JAPAN | NaN | 30.0 | NaN | NaN |
| 5 | 1678-06-18 01:45:00 | 325.0 | NaN | PERU: LIMA,SALINAS-HUAURA,LIMA,CALLAO,CHANCAY | -9.000 | -79.000 | 40.0 | 8.4 | 9.0 | NaN | ... | NaN | 8.4 | NaN | NaN | NaN | PERU | NaN | 160.0 | NaN | NaN |
| 6 | 1678-10-02 00:00:00 | NaN | NaN | JAPAN: SANRIKU,RIKUCHU | 38.600 | 142.000 | NaN | 7.4 | NaN | 1.0 | ... | NaN | NaN | 7.4 | NaN | NaN | JAPAN | NaN | 30.0 | NaN | NaN |
| 7 | 1679-06-04 00:00:00 | NaN | NaN | TURKEY; ARMENIA: DVINA | 40.100 | 44.700 | 15.0 | 5.9 | NaN | 7600.0 | ... | NaN | NaN | 5.9 | NaN | NaN | TURKEY | NaN | 140.0 | NaN | NaN |
| 8 | 1679-09-02 00:00:00 | NaN | NaN | CHINA: HEBEI PROVINCE | 40.000 | 117.000 | NaN | 8.0 | 11.0 | 13162.0 | ... | NaN | 8.0 | NaN | NaN | NaN | CHINA | NaN | 30.0 | NaN | NaN |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 5467 | 2023-01-28 18:14:45 | NaN | NaN | IRAN: KHVOY (KHOY) | 38.424 | 44.909 | 16.0 | 5.9 | 8.0 | 3.0 | ... | 4.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 5468 | 2023-02-06 01:17:35 | 5873.0 | NaN | TURKEY; SYRIA | 37.166 | 37.042 | 17.0 | 7.8 | 9.0 | 48224.0 | ... | 4.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 5469 | 2023-02-06 10:24:49 | NaN | NaN | TURKEY; SYRIA | 38.024 | 37.203 | 10.0 | 7.5 | 9.0 | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 5470 | 2023-02-09 06:28:00 | NaN | NaN | INDONESIA: NEW GUINEA: IRIAN JAYA: JAYAPURA | -2.635 | 140.557 | 22.0 | 5.1 | 8.0 | 4.0 | ... | 1.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 5471 | 2023-02-20 17:04:29 | NaN | NaN | TURKEY; SYRIA | 36.109 | 36.017 | 16.0 | 6.3 | 9.0 | 6.0 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
4416 rows × 42 columns
Il grafico sottostante mostra la dispersione della distribuzione temporale degli eventi sismici.
Ogni punto nel grafico corrisponde al conteggio del numero di terremoti avvenuti prima e durante la data fornita. La dispersione dei punti sulla trama fornisce una rappresentazione visiva della distribuzione degli eventi nel tempo
Questo grafico fornisce una visione immediata della distribuzione temporale degli eventi sismici, consentendo all'utente di identificare trend o periodi di maggiore attività sismici
# Crea un grafico a dispersione con Plotly Express
fig = px.scatter(df_merged, x='Date', y=df_merged.index,
title='Distribuzione Temporale degli Eventi Sismici',
labels={'index': 'Somma del numero di Eventi', 'Date': 'Data'})
fig.update_traces(marker=dict(size=5, opacity=0.5))
fig.update_layout(
xaxis=dict(showline=True, linewidth=2, linecolor='black'),
yaxis=dict(showline=True, linewidth=2, linecolor='black'),
showlegend=False, height=600, width=1000)
# Mostra il grafico
fig.show()
Il prossimo grafico mostra la distribuzione temporale (annuale) degli eventi sismici.
Ogni punto nel grafico corrisponde al conteggio del numero di terremoti avvenuti nell'anno fornito. Come il grafico precedente, anche questo fornisce la dispersione dei punti sulla trama e fornisce una rappresentazione visiva della distribuzione degli eventi nel tempo
Tramite esso è notabile come all'avanzare degli anni, aumenti anche il numero di terremoti registrati ogni anno. Crediamo che ciò sia dovuto al progressivo miglioramento della precisione appartenente alle tecnologie di registrazione dei sismi. Queste tecnologie, aumentando la precisione, possono rilevare eventi con sempre meno magnitudine che probabilmente qualche anno prima non sarebbe stato rilevato.
df_merged['Year'] = pd.to_datetime(df_merged['Date']).dt.year
df_grouped = df_merged.groupby('Year').size().reset_index(name='Earthquakes')
# Crea il grafico con Plotly Express
fig = px.bar(df_grouped, x='Year', y='Earthquakes', labels={'Earthquakes': 'Numero di Terremoti'})
fig.update_layout(
title='Distribuzione del numero di Terremoti per Anno',
xaxis_title='Anno',
yaxis_title='Numero di Terremoti',
height=600, width=1000)
# Mostra il grafico
fig.show()
Analizziamo il numero annuale di decessi causati da eventi sismici mediante un grafico che illustra la relazione tra le morti e gli anni. A tal fine, abbiamo effettuato una suddivisione dei dati in base agli anni e calcolato la somma dei decessi per ciascun anno.
Il grafico presenta una linea che indica la media annuale dei decessi, accompagnata da un'annotazione che fornisce il valore medio. Tale rappresentazione visiva consente di comprenderne la variazione annuale e di confrontare ogni anno rispetto alla media.
earthquake_data = pd.DataFrame({
'Deaths': df_merged['Deaths'],
'Year': df_merged['Date'].dt.year
})
# Group by year and sum the deaths for each year
deaths_per_year = earthquake_data.groupby('Year')['Deaths'].sum().reset_index()
# Calculate the average number of deaths per year
average_deaths_per_year = deaths_per_year['Deaths'].mean()
# Create a line plot using plotly.express
fig = px.line(deaths_per_year, x='Year', y='Deaths',
title='Numero di morti a causa di terremoti ogni anno',
labels={'Deaths': 'Numero di morti', 'Year': 'Anno'},
template='plotly')
# Add a horizontal line for the average
fig.add_shape(type='line',
x0=deaths_per_year['Year'].min(),
x1=deaths_per_year['Year'].max(),
y0=average_deaths_per_year,
y1=average_deaths_per_year,
line=dict(color='red', dash='dash')
)
fig.add_annotation(
x=deaths_per_year['Year'].min()+50,
y=average_deaths_per_year-10,
text=f'In media: {average_deaths_per_year:.2f} morti all\'anno',
font=dict(size=14),
showarrow=True,
arrowhead=2,
ax=50,
ay=-120
)
fig.update_layout(
xaxis=dict(showline=True, linewidth=2, linecolor='black'),
yaxis=dict(showline=True, linewidth=2, linecolor='black'),
showlegend=False, height=700, width=1100
)
fig.update_yaxes(range=[0,deaths_per_year['Deaths'].max()])
# Show the graph
fig.show()
Abbiamo prodotto tre visualizzazioni grafiche per delineare la distribuzione degli eventi sismici.
La prima rappresentazione consiste in una mappa geografica del pianeta Terra, in cui ogni punto rappresenta un singolo evento sismico. La gradazione di tonalità attribuita ai punti è direttamente proporzionale al valore della magnitudo registrata, manifestando un rapporto inversamente proporzionale tra la chiarezza del colore e l'entità della magnitudo. Punti più scuri corrispondono a magnitudini più elevate, mentre punti più chiari indicano magnitudini inferiori.
La seconda rappresentazione consiste in una HeatMap, che visualizza la densità degli eventi sismici in un contesto spaziale. Tale rappresentazione grafica offre una percezione immediata delle regioni con maggiore concentrazione di attività sismica.
Infine, la terza rappresentazione consiste in una breve animazione temporale che illustra l'evoluzione degli eventi sismici nel corso del tempo. Questa dinamica visualizzazione offre un'opportunità unica di esaminare la distribuzione temporale degli eventi sismici, consentendo l'osservazione di eventuali pattern o variazioni nel corso del tempo.
df = df_merged.dropna(subset=['Latitude', 'Longitude', 'Mag'], inplace=False)
fig = px.scatter_geo(df, lat='Latitude', lon='Longitude',
title='Distribuzione Geografica degli Eventi Sismici',
labels={'Latitude': 'Latitudine', 'Longitude': 'Longitudine', 'Mag':'Magnitudine'},
hover_name='Location Name',
color_continuous_scale=px.colors.sequential.Reds,
projection='natural earth',
color='Mag',
opacity=0.7)
fig.update_layout(geo=dict(projection_scale=1, center=dict(lat=0, lon=0)))
fig.update_layout(height=600, width=1000)
fig.show()
Il codice sottostante genera una heatmap che mostra la distribuzione geografica degli eventi sismici. Inizialmente vengono calcolati i valori minimi e massimi delle latitudini e longitudini presenti nel dataset. Successivamente viene creata la mappa e vengono inseriti i dati calcolati.
È interessante notare che la maggior parte degli eventi si verifica sulle coste. Questo è dovuto alla tectonica delle placche e alla presenza di limiti di placca lungo i margini delle masse continentali. Infatti le regioni costiere spesso si trovano vicino ai confini delle placche tettoniche. Questi sono luoghi in cui le placche litosferiche della crosta terrestre interagiscono. Gli eventi sismici sono spesso il risultato della liberazione di energia durante i movimenti delle placche, che possono portare a deformazioni della crosta terrestre e alla formazione di faglie.
Inoltre queste regioni sono influenzate dalla subduzione, un processo in cui una placca litosferica scivola sotto un'altra placca. Questo fenomeno può causare terremoti di grandi dimensioni e anche generare vulcani nelle regioni costiere.
lat_min, lat_max = df_merged['Latitude'].min(), df_merged['Latitude'].max()
lon_min, lon_max = df_merged['Longitude'].min(), df_merged['Longitude'].max()
center_lat = (lat_min + lat_max) / 2
center_lon = (lon_min + lon_max) / 2
fig = px.density_mapbox(df_merged, lat='Latitude', lon='Longitude',
title='Heatmap della Distribuzione Geografica degli Eventi Sismici',
mapbox_style='carto-positron',
color_continuous_scale=px.colors.sequential.Reds,
opacity=0.7, radius=3, zoom=0.9,
center=dict(lat=center_lat+25, lon=center_lon+25))
fig.update_layout(
margin=dict(l=10, r=10, b=10, t=60),
height=600,
width=1000,
coloraxis_colorbar=dict(title='Densità')
)
fig.show()
Come ultimo grafico per la distribuzione geografica abbiamo generato un animazione. Questa mostra tutti gli eventi sismici dal 1800 al 2023 presenti in tutto il mondo.
df_merged['Affected Countries'] = df_merged['Location Name'].str.split(':').str[0]
geo_df = df_merged.dropna(subset=['Latitude', 'Longitude', 'Mag'], inplace=False)
color_scale_limits = [geo_df['Mag'].min(),geo_df['Mag'].max()]
geo_df = geo_df[geo_df['Date'].dt.year >= geo_df['Date'].max().year-50]
fig_map = px.scatter_geo(geo_df,
lat='Latitude',
lon='Longitude',
title='Distribuzione Geografica degli Eventi Sismici negli ultimi 50 anni',
labels={'Latitude': 'Latitudine', 'Longitude': 'Longitudine'},
hover_name='Location Name',
animation_frame=geo_df['Date'].dt.year,
color='Mag',
color_continuous_scale=px.colors.sequential.Reds,
range_color=color_scale_limits)
fig_map.update_geos(projection_type="natural earth")
fig_map.update_coloraxes(colorbar=dict(title='Magnitudine'))
fig_map.update_layout(width=1000, height=600)
fig_map.show()
Abbiamo deciso di rappresentare tramite un scala di colori il magnitudo presente nelle varie nazioni. Ogni nazione nell'immagine viene colorata con una tonalità di blue che varia in base all'intensità del magnitudo. Un colore più chiaro indica un magnitudo basso mentre un blue scuro indica un magnitudo alto.
countries_list = df_merged['Affected Countries'].str.split('; ', expand=True).stack().reset_index(level=1, drop=True).rename('AffCountry')
df_split = df_merged.drop('Affected Countries', axis=1).join(countries_list)
# Calcolo della media delle magnitudini per ogni paese
df_avg_mag = df_split.groupby('AffCountry')['Mag'].mean().reset_index()
# Creazione del grafico choropleth
fig = px.choropleth(df_avg_mag,
locations='AffCountry',
locationmode='country names',
color='Mag',
title='Magnitudine media per Paese',
color_continuous_scale=px.colors.sequential.Blues)
fig.update_coloraxes(colorbar=dict(title='Magnitudine Media'))
fig.update_layout(height=600, width=1000)
fig.show()
L'analisi corrente si propone di esaminare le magnitudini negli stati più gravemente colpiti mediante l'utilizzo di un BoxPlot. Ciascun "box" nel diagramma rappresenta la distribuzione delle magnitudini relative agli eventi sismici in uno specifico paese. Le linee che si estendono dai box indicano la dispersione delle magnitudini degli eventi sismici, evidenziando eventuali valori estremi o "outlier".
Il confronto tra i box e le relative annotazioni agevola l'identificazione di distribuzioni di magnitudine più focalizzate o diffuse. Paesi caratterizzati da "whiskers" più estese e mediana più elevata possono essere interpretati come regioni con una variabilità maggiore e magnitudini medie più elevate degli eventi sismici.
conteggio_paesi = df_merged['Affected Countries'].value_counts().reset_index()
conteggio_paesi.columns = ['Paese', 'Numero Terremoti']
top_10_paesi = conteggio_paesi.head(10)['Paese'].tolist()
df_top_10 = df_merged[df_merged['Affected Countries'].isin(top_10_paesi)].copy()
df_top_10['Affected Countries'] = pd.Categorical(df_top_10['Affected Countries'], categories=top_10_paesi, ordered=True)
df_top_10 = df_top_10.sort_values(by='Affected Countries')
fig = px.box(df_top_10, x='Affected Countries', y='Mag', title='Box Plot delle Magnitudini dei 10 Paesi più colpiti',
category_orders={'Affected Countries': top_10_paesi})
for i, row in conteggio_paesi.iterrows():
if row['Paese'] in top_10_paesi:
fig.add_annotation(x=row['Paese'], y=df_top_10['Mag'].min()-1,
text=row["Numero Terremoti"],
showarrow=False, font=dict(size=13))
fig.update_yaxes(range=[df_top_10['Mag'].min()-1.5, len(top_10_paesi)])
fig.update_layout(yaxis_title="Magnitudine", xaxis_title="10 Paesi più colpiti", height=800, width=1100,
xaxis=dict(showline=True, linewidth=2, linecolor='black'),
yaxis=dict(showline=True, linewidth=2, linecolor='black'))
fig.show()
Nel presente contesto, si procede con la generazione di un grafico di densità termica (heatmap) finalizzato a offrire un'illustrazione visiva della distribuzione temporale delle magnitudini relative agli eventi sismici, diligentemente catalogati nel DataFrame df_merged.
Attraverso l'impiego della libreria Plotly, è stato concretizzato un Heatmap in cui la variabile indipendente (asse delle ascisse, x) è dedicata all'anno di occorrenza degli eventi sismici, ricavato mediante l'estrazione dalla colonna 'Date'. Simultaneamente, la variabile dipendente (asse delle ordinate, y) rappresenta le magnitudini degli eventi sismici ('Mag'). A ulteriore impegno della rappresentazione grafica, sono stati introdotti istogrammi marginali sia lungo l'asse x che y, agevolando così l'osservazione approfondita delle distribuzioni marginali delle grandezze coinvolte nell'analisi.
fig = px.density_heatmap(df_merged,
x=df_merged['Date'].dt.year,
y='Mag',
marginal_x='histogram',
marginal_y='histogram',
title='Heatmap Temporale delle Magnitudini',
nbinsx=90, nbinsy=20)
fig.update_layout(
xaxis=dict(range=[1897, datetime.now().year], showline=True, linewidth=2, linecolor='black'),
yaxis=dict(range=[3, 9], showline=True, linewidth=2, linecolor='black'),
yaxis_title="Magnitude",
xaxis_title="Anno",
height=500, width=1000
)
fig.update_coloraxes(colorbar=dict(title='Numero di terremoti'))
fig.show()
Il codice in esame si concentra sull'analisi della magnitudine media degli eventi sismici, tenendo conto delle circostanze specifiche in cui tali eventi si verificano. In particolare, si valuta la presenza di due condizioni distintive: la possibilità di tsunami (Tsu) e l'eventuale attività di eruzioni vulcaniche (Vol).
La descrizione dettagliata delle variabili calcolate è la seguente:
mag_mean_without_both: Questo valore rappresenta la magnitudine media degli eventi sismici che non sono associati né a condizioni di tsunami né a eruzioni vulcaniche. In altre parole, si tratta di una valutazione della magnitudine in situazioni in cui non sono verificate entrambe le condizioni contemporaneamente.
mag_mean_with_tsunami: Questo parametro indica la magnitudine media degli eventi sismici che si sono verificati in presenza di condizioni di tsunami. Si focalizza sull'analisi delle magnitudini specificamente correlate a eventi sismici che causano tsunami.
mag_mean_with_volcano: Questo valore rappresenta la magnitudine media degli eventi sismici che sono avvenuti in concomitanza con condizioni di eruzione vulcanica. Si concentra sull'analisi delle magnitudini degli eventi sismici che si verificano in presenza di attività vulcaniche.
mag_mean_without_both = df_merged['Mag'].mean()
mag_mean_with_tsunami = df_merged[df_merged['Tsu'].notnull()]['Mag'].mean()
mag_mean_with_volcano = df_merged[df_merged['Vol'].notnull()]['Mag'].mean()
mag_mean_with_both = df_merged[df_merged['Tsu'].notnull() & df_merged['Vol']]['Mag'].mean()
data = {'Tsunami': ['Without both', 'With Tsunami', 'With Volcano', 'With both'],
'Average Magnitude': [mag_mean_without_both, mag_mean_with_tsunami, mag_mean_with_volcano, mag_mean_with_both]}
avg_mag_df = pd.DataFrame(data)
fig = px.bar(avg_mag_df, x='Tsunami', y='Average Magnitude',
title='Magnitudine media dei terremoti che causano Tsunami o Eruzioni Vulcaniche',
labels={'Average Magnitude': 'Magnitudine Media', 'Tsunami':'Codizioni Tsunami ed Eruzioni Vulcaniche'})
fig.update_layout(
height=700, width=1000,
xaxis=dict(showline=True, linewidth=2, linecolor='black'),
yaxis=dict(showline=True, linewidth=2, linecolor='black'),
)
fig.show()
La correlazione tra terremoti, tsunami ed eruzioni vulcaniche può essere compresa attraverso meccanismi geologici interconnessi. Ad esempio, un terremoto può causare uno tsunami attraverso procedure che includono la subduzione delle placche tettoniche (sprofondamento di una zolla al di sotto di quella immediatamente adiacente). Durante la subduzione, la placca oceanica può essere spinta sotto un'altra placca, dando inizio a un terremoto sottomarino. Questo movimento può provocare aggiustamenti nel fondale marino, con conseguente formazione di un'onda di tsunami.
Inoltre, alcune eruzioni vulcaniche possono essere provocate da terremoti. Lo stress all'interno delle rocce e dei gas sotto il suolo terrestre può aumentare a causa dell'interesse sismico, provocando il rilascio di magma e un'eruzione vulcanica. In questo contesto, il passatempo sismico può fungere da catalizzatore per le tecniche vulcaniche.
In ogni caso, esiste una chiara interconnessione tra le forze geologiche che possono essere scatenate dagli eventi sismici, dando impulso a fenomeni quali tsunami ed eruzioni vulcaniche.
# Crea una nuova colonna 'Evento' basata sui valori in 'tsu' e 'vul'
df_pie = df_merged
df_pie['Event'] = df_pie.apply(lambda row: 'Entrambi' if (pd.notna(row['Tsu'])) and (pd.notna(row['Vol']))
else ('Tsunami' if pd.notna(row['Tsu'])
else ('Eruzione vulcanica' if pd.notna(row['Vol']) > 0
else 'Nessun evento')), axis=1)
# Creazione del grafico a torta
fig = px.pie(df_pie, names='Event', title='Distribuzione di Eventi Sismici che hanno causato Tsunami o Eruzioni Vulcaniche')
fig.update_traces(textinfo='percent', insidetextorientation='radial', textfont_size=16)
fig.update_layout(height=500, width=800, legend=dict(font=dict(size=16)))
fig.show()
La mappa termica è suddivisa in bin, ciascuno dei quali rappresenta una combinazione di profondità e magnitudine degli eventi sismici. La scala cromatica di ciascun bin indica la densità di eventi sismici in quella specifica regione del grafico, dove regioni più rosse indicano un maggiore numero di eventi.
Per ottimizzare la visualizzazione, abbiamo apportato le seguenti personalizzazioni:
fig = px.density_heatmap(df_merged, y='Focal Depth (km)', x='Mag',
title='Heatmap Relazione tra Profondità e Magnitudine',
labels={'Focal Depth (km)': 'Profondità', 'Mag': 'Magnitudine'},
color_continuous_scale=px.colors.sequential.Reds,
nbinsx=100, nbinsy=200)
fig.update_yaxes(range=[0,100])
fig.update_xaxes(range=[3.8,8.5])
fig.update_layout(
xaxis=dict(showline=True, linewidth=2, linecolor='black'),
yaxis=dict(showline=True, linewidth=2, linecolor='black'),
width=1000, height=500)
fig.show()
Il codice esegue un'analisi sulla relazione tra la magnitudine degli eventi sismici e la loro intensità MMI (Modified Mercalli Intensity).
Inizialmente, vengono eliminati i dati che presentano valori mancanti nell'intensità MMI, generando un nuovo insieme di dati denominato "filtered_data".
Successivamente, i dati filtrati vengono raggruppati in base alla magnitudine degli eventi sismici, e viene calcolata la media dell'intensità MMI per ciascun gruppo. Questo processo crea un nuovo set di dati chiamato "grouped_data".
Successivamente, viene eseguita una regressione lineare sui dati raggruppati per identificare la tendenza nella relazione tra la magnitudine e l'intensità MMI. I coefficienti della regressione, ovvero la pendenza (slope) e l'intercetta (intercept), vengono calcolati.
Infine, viene creato un grafico a barre utilizzando Plotly Express che rappresenta la relazione tra la magnitudine e l'intensità MMI. Viene anche tracciata una linea di regressione sulla base dei coefficienti calcolati, evidenziando la tendenza generale della relazione. Il grafico fornisce un'indicazione visiva della correlazione tra questi due parametri sismici.
L'analisi considera la relazione tra due importanti parametri che caratterizzano gli eventi sismici: l'Intensità Mercalli Modificata (MMI) e la magnitudo. La magnitudo di un terremoto rappresenta la quantità totale di energia rilasciata durante l’evento sismico. È un valore numerico che aumenta all’aumentare dell’energia rilasciata. L’intensità MMI, invece, valuta l’impatto sismico su luoghi specifici. Misura gli effetti degli eventi sismici sulla superficie terrestre e sugli edifici. La scala MMI è divisa in categorie che vanno da I (impercettibile) a XII (distruzione totale).
Il codice esegue una regressione lineare tra magnitudo e intensità MMI per mostrare la tendenza generale di come la magnitudo di un terremoto può influenzare l'intensità percepita in determinate località.
In termini pratici, un terremoto di magnitudo maggiore tende ad avere effetti più intensi sulla superficie terrestre e sugli edifici, aumentando così il valore dell'intensità del MMI. È importante però notare che l’intensità percepita può variare a seconda della distanza dal punto di origine dell’evento sismico e della geologia locale.
filtered_data = df_merged.dropna(subset=['MMI Int'], inplace=False)
grouped_data = filtered_data.groupby('Mag')['MMI Int'].mean().reset_index()
x = grouped_data['Mag']
y = grouped_data['MMI Int']
coefficients = np.polyfit(x, y, 1)
slope, intercept = coefficients
fig = px.bar(grouped_data, x='Mag', y='MMI Int', title='Relazione tra intensità MMI e Magnitudine')
x_values = np.linspace(x.min(), x.max(), 100)
y_values = slope * x_values + intercept
fig.add_trace(go.Scatter(
x=x_values,
y=y_values,
mode='lines',
name='Regression Line',
line=dict(color='red', dash='dot')
))
fig.update_layout(xaxis_title='Magnitudine', yaxis_title='Intensità MMI media', width=1000, height=500,
xaxis=dict(showline=True, linewidth=2, linecolor='black'),
yaxis=dict(showline=True, linewidth=2, linecolor='black'))
fig.update_xaxes(range=[grouped_data['Mag'].min()-.1, grouped_data['Mag'].max()+.1])
fig.show()
Per il seguente grafico abbiamo filtrato le righe del DataFrame df_merged per eliminare quelle che presentano dati mancanti nella magnitudo ('Mag') e nel nome della località ('Location Name'). Il risultato di questa operazione è memorizzato nel DataFrame "filtered_df".
Successivamente, il DataFrame filtrato viene ordinato in base alla magnitudo in ordine decrescente e vengono selezionate le prime 10 righe. Il nuovo DataFrame risultante è chiamato "top_10_df" e contiene le informazioni sui dieci terremoti più potenti.
Utilizzando la libreria Plotly Express, viene creato un grafico a barre in cui le località sono sull'asse delle ascisse (x) e le magnitudini sono sull'asse delle ordinate (y). Il titolo del grafico è "10 Terremoti più Potenti per Località", e sono state aggiunte etichette per chiarezza.
Per gestire le differenze di scala tra le magnitudini, l'asse delle ordinate è impostato con una scala logaritmica. Questo permette di visualizzare più chiaramente le differenze di magnitudo anche in presenza di un ampio intervallo di valori.
# Filtra righe con dati validi su Magnitude e Location Name
filtered_df = df_merged.dropna(subset=['Mag', 'Location Name'], inplace=False)
# Ordina il DataFrame in base alla magnitudo in ordine decrescente
top_10_df = filtered_df.sort_values(by='Mag', ascending=False).head(10)
# Crea il grafico a barre
fig = px.bar(top_10_df, x='Location Name', y='Mag',
title='10 Terremoti più Potenti per Località',
labels={'Mag': 'Magnitudine', 'Location Name': 'Località'})
# aggiunta della scala logaritmica sull'asse y per gestire le differenze di scala
fig.update_layout(yaxis_type='log', width=1100, height=800,
xaxis=dict(showline=True, linewidth=2, linecolor='black'),
yaxis=dict(showline=True, linewidth=2, linecolor='black'))
# Mostra il grafico
fig.show()
Abbiamo deciso di analizzare i 25 terremoti più letali. Abbiamo selezionato le colonne pertinenti ('Affected Countries' e 'Deaths') dal DataFrame df_merged e creato un nuovo DataFrame chiamato earthquake_data. Successivamente, raggruppa i dati in base ai paesi colpiti ('Affected Countries'), somma il numero di morti per ciascun paese e ordina i risultati in modo decrescente. I primi 25 paesi più letali sono quindi selezionati e memorizzati nel DataFrame top_25_deadliest.
# Select relevant columns
earthquake_data = df_merged[['Affected Countries', 'Deaths']]
# Group by location and sum the deaths for each location
grouped_data = earthquake_data.groupby('Affected Countries')['Deaths'].sum().reset_index()
# Sort the data by the number of deaths in descending order and take the top 25
top_25_deadliest = grouped_data.sort_values(by='Deaths', ascending=False).head(25)
# Create the horizontal bar chart using plotly.express
fig = px.bar(top_25_deadliest,
y='Affected Countries',
x='Deaths',
orientation='h',
title='I 25 terremoti più letali per paese colpito',
labels={'Deaths': 'Numero di Morti', 'Affected Countries': 'Paese Colpito'},
template='plotly',
opacity=0.7)
fig.update_layout(width=1000, height=700,
xaxis=dict(showline=True, linewidth=2, linecolor='black'),
yaxis=dict(showline=True, linewidth=2, linecolor='black'))
# Show the graph
fig.show()
In questo grafico, la profondità focale è sull'asse orizzontale (x), mentre la magnitudine è sull'asse verticale (y). Le dimensioni degli assi sono modificate specificando gli estremi e gli step desiderati. Infine, il layout del grafico viene personalizzato impostando uno sfondo nero per gli assi e specificando le dimensioni complessive del grafico.
Il risultato è visualizzato per fornire una rappresentazione visiva della relazione tra la profondità focale e la magnitudine degli eventi sismici.
# Seleziona le colonne necessarie per il grafico
data_for_plot = df_merged[['Mag', 'Focal Depth (km)']]
# Rimuovi righe con valori mancanti in una delle colonne
data_for_plot = data_for_plot.dropna()
# Crea il grafico con plotly.express invertendo gli assi
fig = px.scatter(data_for_plot, x='Focal Depth (km)', y='Mag',
title='Relazione tra Profondità Focale e Magnitudine',
labels={'Focal Depth (km)': 'Profondità Focale (km)', 'Mag': 'Magnitudine'})
# Imposta gli estremi e gli step degli assi
fig.update_yaxes(range=[data_for_plot['Mag'].min()-.2, data_for_plot['Mag'].max()+.2], dtick=1)
fig.update_xaxes(range=[-1, data_for_plot['Focal Depth (km)'].max()+10], dtick=100)
fig.update_layout(height=700, width=1000,
xaxis=dict(showline=True, linewidth=2, linecolor='black'),
yaxis=dict(showline=True, linewidth=2, linecolor='black')
)
# Mostra il grafico
fig.show()
Il grafico mostra l'andamento del danno totale dei terremoti nel corso degli anni, consentendo una rapida identificazione di eventuali tendenze o modelli. Attraverso questo grafico, è possibile identificare tendenze nel danno causato dai terremoti nel corso del tempo. Ad esempio, picchi notevoli potrebbero indicare anni con un numero significativo di terremoti di grande entità o potrebbe evidenziare periodi di intensa attività sismica. La sua natura interattiva consente agli utenti di esplorare più dettagliatamente il grafico e di ottenere informazioni specifiche su singoli punti o intervalli temporali.
earthquake_data = pd.DataFrame({
'Total Damage ($Mil)': df_merged['Total Damage ($Mil)'],
'Year': df_merged['Date'].dt.year
})
# Group by year and sum the total damages for each year
damages_per_year = earthquake_data.groupby('Year')['Total Damage ($Mil)'].sum().reset_index()
# Create a line plot using plotly.express
fig = px.line(damages_per_year, x='Year', y='Total Damage ($Mil)',
title='Danni Totali dei terremoti ogni anno',
labels={'Total Damage ($Mil)': 'Danni Totali (Milioni di $)', 'Year': 'Anno'},
template='plotly')
fig.update_xaxes(range=[1970, damages_per_year['Year'].max()])
fig.update_yaxes(range=[0, damages_per_year['Total Damage ($Mil)'].max()])
fig.update_layout(height=700, width=1000,
xaxis=dict(showline=True, linewidth=2, linecolor='black'),
yaxis=dict(showline=True, linewidth=2, linecolor='black')
)
# Show the graph
fig.show()